﻿using System;
using System.Collections.Generic;
using System.Text;

namespace KBEngine.Common
{
    /// <summary>
    /// 使用样例：
    /// var w = KBEngine.Common.SpaceViewer(ComponentType.cellappmgr)
    /// w.connect("127.0.0.1", 12345) // host, port -> got from Machines.ComponentInfo.{intaddr,intport}
    /// w.requireQuerySPACE("root")
    /// w.processOne()
    /// w.watchData
    /// </summary>
    public class SpaceViewer : ServerApp
    {
        private readonly ComponentType _componentType;
        ViewerData _spaceViewerData;
        public SpaceViewer(ComponentType componentType)
        {
            registerMsg(Define.CONSOLE_PROFILECB_MSGID, onSpaceViewerMsg);
            _componentType = componentType;
            _spaceViewerData = new ViewerData();
            System.Diagnostics.Debug.Assert(Array.Exists(Enum.GetNames(typeof(CMD_ID_querySpaceViewer)), _componentType.ToString().Equals));
        }

        public void clearSpaceViewerData()
        {
            _spaceViewerData = new ViewerData();
        }

        public void requireQuerySpaceViewer()
        {
            var querySpaceViewerID = (ushort)Enum.Parse(typeof(CMD_ID_querySpaceViewer), _componentType.ToString());
            Bundle bundle = Bundle.createObject();
            bundle.newMessage(FixedMsg.Get(querySpaceViewerID));
            send(bundle);
        }

        private void onSpaceViewerMsg(MemoryStream ms)
        {
            _spaceViewerData = new ViewerData();
            _spaceViewerData.componentType = ms.readInt32();
            _spaceViewerData.componentID = ms.readInt64();
            var cellapps = _spaceViewerData.cellapp;
            while (!ms.readEOF())
            {
                var CellAppCID = ms.readUint64();
                var SpacesSize = ms.readUint32();
                var cellapp = new CellApp();
                cellapp.SpacesSize = SpacesSize;
                cellapps[CellAppCID] = cellapp;

                for (int i = 0; i < SpacesSize; i++)
                {
                    var SpaceID = ms.readUint32();
                    var SpacePath = ms.readString();
                    var ScriptModuleName = ms.readString();
                    var SpaceCellSize = ms.readUint32();
                    var space = new Space();
                    cellapp.spaces.Add(SpaceID, space);
                    space.SpacePath = SpacePath;
                    space.ScriptModuleName = ScriptModuleName;
                    for (int j = 0; j < SpaceCellSize; j++)
                    {
                        var CELL_ID = ms.readUint32();
                        space.CELL_ID.Add(CELL_ID);
                    }
                }
            }
        }

        public class ViewerData
        {
            public int componentType;
            public long componentID;
            public Dictionary<ulong, CellApp> cellapp = new Dictionary<ulong, CellApp>();
            public byte type;
            public string path = string.Empty;
            public Dictionary<string, string> values = new Dictionary<string, string>();
            public List<string> keys = new List<string>();
        }
        public class CellApp
        {
            public uint SpacesSize;
            public Dictionary<uint, Space> spaces = new Dictionary<uint, Space>();
        }
        public class Space
        {
            public List<uint> CELL_ID = new List<uint>();
            public string SpacePath = string.Empty;
            public string ScriptModuleName = string.Empty;
        }

        private enum CMD_ID_querySpaceViewer : ushort
        {
            cellappmgr = 50003,
            cellapp = 50005,
        }
    }

    /// <summary>
    /// 获取CellAppMgr中space信息
    /// 使用样例：
    /// var w = KBEngine.Common.CellAppMgrViewer(ComponentType.cellappmgr, 1)
    /// w.connect("127.0.0.1", 65151)
    /// w.requireQueryCellAppMgrViewer()
    /// w.processOne()
    /// </summary>
    public class CellAppMgrViewer : ServerApp
    {
        private readonly ComponentType _componentType;
        private readonly uint _spaceID;
        ViewerData _cellAppMgrViewerData;
        public CellAppMgrViewer(ComponentType componentType, uint spaceID)
        {
            registerMsg(Define.CONSOLE_PROFILECB_MSGID, onCellAppMgrViewerMsg);
            _cellAppMgrViewerData = new ViewerData();
            _spaceID = spaceID;
            _componentType = componentType;
        }
        public void clearCellAppMgrViewerData()
        {
            _cellAppMgrViewerData = new ViewerData();
        }
        public void requireQueryCellAppMgrViewer()
        {
            Bundle bundle = Bundle.createObject();
            bundle.newMessage(FixedMsg.Get("Cellappmgr::setSpaceViewer"));
            bundle.writeInt8(0);
            bundle.writeUint32(_spaceID);
            send(bundle);
        }
        private void onCellAppMgrViewerMsg(MemoryStream ms)
        {
            _cellAppMgrViewerData = new ViewerData();
            _cellAppMgrViewerData.componentType = ms.readInt32();
            _cellAppMgrViewerData.componentID = ms.readInt64();
            while (!ms.readEOF())
            {
                var cellApp = new CellApp();
                cellApp.cellappID = ms.readUint64();
                cellApp.spaceID = ms.readUint32();
                cellApp.geomapping = ms.readString();
                cellApp.scriptModuleName = ms.readString();
                cellApp.cells_Size = ms.readUint32();
                for (int i = 0; i < cellApp.cells_Size; i++)
                {
                    var cellID = ms.readUint32();
                    cellApp.cellID.Add(cellID);
                }
                _cellAppMgrViewerData.cellApps.Add(cellApp);
            }
        }

        public class ViewerData
        {
            public int componentType;
            public long componentID;
            public List<CellApp> cellApps = new List<CellApp>();

        }
        public class CellApp
        {
            public ulong cellappID;
            public uint spaceID;
            public string geomapping = string.Empty;
            public string scriptModuleName = string.Empty;
            public uint cells_Size;
            public List<uint> cellID = new List<uint>();
        }
    }

    /// <summary>
    /// 获取cellapp中entity信息
    /// 使用样例：
    /// var w = KBEngine.Common.CellViewer(ComponentType.cellappmgr, 5)
    /// w.connect("127.0.0.1", 42225)
    /// w.requireQueryCellViewer()
    /// w.processOne()
    /// </summary>
    public class CellViewer : ServerApp
    {
        private readonly ComponentType _componentType;
        private readonly uint _spaceID;
        ViewerData _cellViewerData;
        private int a = 0;
        public CellViewer(ComponentType componentType, uint spaceID)
        {
            registerMsg(Define.CONSOLE_PROFILECB_MSGID, onCellViewerMsg);
            _cellViewerData = new ViewerData();
            _spaceID = spaceID;
            _componentType = componentType;
            System.Diagnostics.Debug.Assert(Array.Exists(Enum.GetNames(typeof(CMD_ID_querySpaceViewer)), _componentType.ToString().Equals));
        }
        public void clearCellViewerData()
        {
            _cellViewerData = new ViewerData();
        }
        public void requireQueryCellViewer()
        {
            var querySpaceViewerID = (ushort)Enum.Parse(typeof(CMD_ID_querySpaceViewer), _componentType.ToString());
            Bundle bundle = Bundle.createObject();
            bundle.newMessage(FixedMsg.Get(querySpaceViewerID));
            bundle.writeInt8(0);
            bundle.writeUint32(_spaceID);
            bundle.writeUint32(0);
            send(bundle);
        }
        private void onCellViewerMsg(MemoryStream ms)
        {
            _cellViewerData = new ViewerData();
            _cellViewerData.componentType = ms.readInt32();
            _cellViewerData.componentID = ms.readInt64();
            _cellViewerData.cpType = ms.readInt32();
            while (!ms.readEOF())
            {
                if (a == 0)
                {
                    var scriptModules_size = ms.readUint32();
                    _cellViewerData.cellAppInfo.scriptModules_size = scriptModules_size;
                    for (int i = 0; i < scriptModules_size; i++)
                    {
                        var UType = ms.readUint16();
                        _cellViewerData.cellAppInfo.UType.Add(UType);
                        if (_cellViewerData.cpType == 0)
                            _cellViewerData.cellAppInfo.Name.Add(ms.readString());
                    }
                    ++a;
                }
                else
                {
                    var viewerIter = ms.readInt32();
                    var bools = ms.readInt8() == 1;
                    var entityInfo = new EntityInfo();
                    _cellViewerData.spaceEntity.Add(viewerIter, entityInfo);
                    entityInfo.update = bools;
                    if (bools)
                    {
                        entityInfo.pEntity = ms.readUint16();
                        entityInfo.position = ms.readVector3();
                        entityInfo.direction = ms.readVector3();
                    }
                }
            }
        }

        public class ViewerData
        {
            public int componentType;
            public long componentID;
            public int cpType;
            public CellApp cellAppInfo;
            public Dictionary<int, EntityInfo> spaceEntity = new Dictionary<int, EntityInfo>();
        }
        public class CellApp
        {
            public uint scriptModules_size;
            public List<ushort> UType = new List<ushort>();
            public List<string> Name = new List<string>();
        }
        public class EntityInfo
        {
            public bool update;
            public ushort pEntity;
            public Vector3 position = Vector3.zero;
            public Vector3 direction = Vector3.zero;
        }
        private enum CMD_ID_querySpaceViewer : ushort
        {
            cellappmgr = 50003,
            cellapp = 50005,
        }
    }
}
